#include <stdlib.h>
#include <mpi.h>
#include "operation_list.h"

void init_operation_list(operation_list *list) {
  list->head = NULL;
  list->size = 0;
}

int insert_operation(operation_list *list, operation_message msg) {
  int size = -1;
  operation_node *new_head = (operation_node*) malloc(sizeof(operation_node));

  if (new_head != NULL) {
    new_head->message.operation = msg.operation;
    new_head->message.content = msg.content;
    new_head->message.server = msg.server;

    new_head->next = list->head;
    list->head = new_head;

    size = list->size++;
  }

  return size;
}

int delete_operation(operation_list *list) {
  int size = 0;

  operation_node *old_head = list->head;
  
  if (old_head != NULL) {
    list->head = old_head->next;

    free(old_head);

    size = list->size--;
  }

  return size;
}

operation_message get_operation(operation_list list) {
  operation_message msg;

  msg.operation = list.head->message.operation;
  msg.content = list.head->message.content;
  msg.server = list.head->message.server;

  return msg;
}

void build_operation_datatype(operation_message *msg, MPI_Datatype *msg_type_ptr) {

  int block_lengths[3];
  MPI_Aint displacements[3];
  MPI_Aint addresses[4];
  MPI_Datatype typelist[3];

  typelist[0] = MPI_INT;
  typelist[1] = MPI_INT;
  typelist[2] = MPI_INT;

  block_lengths[0] = block_lengths[1] = block_lengths[2] = 1;

  MPI_Address(msg, &addresses[0]);
  MPI_Address(&(msg->operation), &addresses[1]);
  MPI_Address(&(msg->content), &addresses[2]);
  MPI_Address(&(msg->server), &addresses[3]);

  displacements[0] = addresses[1] - addresses[0];
  displacements[1] = addresses[2] - addresses[0];
  displacements[2] = addresses[3] - addresses[0];

  MPI_Type_struct(3, block_lengths, displacements, typelist, msg_type_ptr);

  MPI_Type_commit(msg_type_ptr);
}
